package com.ruyuan.dfs.namenode.editslog;

import com.ruyuan.dfs.common.utils.FileUtil;
import com.ruyuan.dfs.namenode.config.NameNodeConfig;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.List;

/**
 * @ClassName DoubleMappBuffer
 * @Author kebukeyi
 * @Date 2022/6/3 13:03
 * @Description
 * @Version 1.0.0
 */
@Slf4j
public class DoubleMappBuffer {

    private NameNodeConfig nameNodeConfig;
    private EditLogMappBuffer currentBuffer;
    private EditLogMappBuffer syncBuffer;

    public DoubleMappBuffer(NameNodeConfig nameNodeConfig, List<EditslogInfo> editLogInfos) {
        this.nameNodeConfig = nameNodeConfig;
        long startTxid = 1;
        if (editLogInfos.size() != 0) {
            EditslogInfo tailEditslogInfo = editLogInfos.get(editLogInfos.size() - 1);
            startTxid = tailEditslogInfo.getEnd() + 1;
            //try {
            //    List<EditLogWrapper> editLogWrappers = EditLogWrapper.parseFrom(FileUtil.readBuffer(tailEditslogInfo.getName()));
            //    for (EditLogWrapper editLogWrapper : editLogWrappers) {
            //        position = Math.max(editLogWrapper.getEndPosition(), position);
            //        startTxid = Math.max(editLogWrapper.getTxId(), startTxid);
            //    }
            //    if (editLogWrappers.size() != 0) {
            //        startTxid++;
            //    }
            //} catch (IOException e) {
            //    e.printStackTrace();
            //}
        }
        //currentBuffer :  0-99  => fileName
        this.currentBuffer = new EditLogMappBuffer(nameNodeConfig, startTxid, startTxid + nameNodeConfig.getDEFAULT_EDITLOG_COUNT() - 1, 0);
        // syncBuffer : 100 - 199   => fileName
        this.syncBuffer = new EditLogMappBuffer(nameNodeConfig, startTxid + nameNodeConfig.getDEFAULT_EDITLOG_COUNT(), startTxid + nameNodeConfig.getDEFAULT_EDITLOG_COUNT() * 2 - 1, 0);
    }

    /**
     * 写入一条editlog
     */
    public void write(EditLogWrapper editLog) throws IOException {
        log.debug("editlog buffer写了一条日志[{}]", editLog);
        currentBuffer.write(editLog);
    }

    /**
     * 交换两块缓冲区
     */
    public void setReadyToSync() {
        EditLogMappBuffer temp = currentBuffer;
        currentBuffer = syncBuffer;
        syncBuffer = temp;
    }

    /**
     * 把缓冲区的editlog数据刷新到磁盘
     */
    public EditslogInfo flush() throws IOException {
        log.debug("缓冲区触发flush");
        EditslogInfo editslogInfo = syncBuffer.flush();
        //关闭
        syncBuffer.close();
        //生产一个新的buffer
        syncBuffer = new EditLogMappBuffer(nameNodeConfig, editslogInfo.getStart() + nameNodeConfig.getDEFAULT_EDITLOG_COUNT() * 2,
                editslogInfo.getStart() + nameNodeConfig.getDEFAULT_EDITLOG_COUNT() * 3 - 1, 0);
        return editslogInfo;
    }

    /**
     * 是否可以刷新磁盘
     *
     * @return 是否可以刷磁盘
     */
    public boolean shouldForceSync() {
        return currentBuffer.count() >= nameNodeConfig.getDEFAULT_EDITLOG_COUNT();
    }

    public List<EditLogWrapper> getCurrentEditLog() {
        return currentBuffer.getCurrentEditLog();
    }

}
